﻿using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace Enterprises.Wpf.Sample.UserControls.Controls
{
    /// <summary>
    /// CanvasView.xaml 的交互逻辑
    /// </summary>
    public partial class CanvasView : System.Windows.Controls.UserControl, INotifyPropertyChanged
    {
        private double canvasWidth = 600;
        private double canvasHeight = 450;
        private double paddingWidth = 40;
        private double arrowWidth = 5;

        private Line XAxis;
        private Line YAxis;
        private Polyline polyline;

        public CanvasView()
        {
            InitializeComponent();
            InitData();
            DrawXY();
            DrawArrow();
            DrawXRule();
            DrawYRule();
            DataContext = this;
        }

        void InitData()
        {
            Points = new PointCollection();
            canvasWidth = this.Width - 40;
            canvasHeight = this.Height - 40;

            var binding = new Binding("Points")
            {
                Source = this, // 假设DataContext就是MainWindow实例
                Mode = BindingMode.OneWay, // 或者TwoWay，根据实际需求
                UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
            };

            polyline = new Polyline()
            {
                Stroke = Brushes.Blue,
                StrokeThickness = 1,
            };

            polyline.SetBinding(Polyline.PointsProperty, binding);
           
            canvas.Children.Add(polyline);
            canvas.MouseLeftButtonDown -= CanvasMouseLeftButtonDown;
            canvas.MouseLeftButtonDown += CanvasMouseLeftButtonDown;

            canvas.MouseMove -= CanvasMouseMove;
            canvas.MouseMove += CanvasMouseMove;
            canvas.MouseUp -= CanvasMouseUp;
            canvas.MouseUp += CanvasMouseUp;
        }

        private void CanvasMouseUp(object sender, MouseButtonEventArgs e)
        {
            ControledShape = null;
        }

        /// <summary>
        /// 拖到点.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CanvasMouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed && ControledShape != null)
            {
                var point = e.GetPosition(canvas);
                var oldPoint = ((EllipseGeometry)ControledShape.Data).Center;
                ControledShape.Data = new EllipseGeometry(point, 2, 2);

                Points.Remove(oldPoint);
                Points.Add(point);
                Points = new PointCollection(Points.OrderBy(p => p.X));
            }
        }

        internal Path? ControledShape { get; set; }

        /// <summary>
        /// 控制点按下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void Graphical_MouseDown(object sender, MouseButtonEventArgs e)
        {
            ControledShape = sender as Path;
            e.Handled = true;
        }

        /// <summary>
        /// 鼠标按下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CanvasMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            // 双击增加点.
            if (sender is Canvas canvasPanel && e.ClickCount == 2)
            {
                var point = e.GetPosition(canvasPanel);
                if (point.X < paddingWidth
                    || point.Y < paddingWidth
                    || point.X > canvasWidth - paddingWidth
                    || point.Y > canvasHeight - paddingWidth)
                {
                    return;
                }

                Points.Add(new Point(point.X, point.Y));
                Points = new PointCollection(Points.OrderBy(p=>p.X));

                // 增加小红点
                var shape = new Path() { Data = new EllipseGeometry(point, 2, 2), Cursor = Cursors.SizeAll };
                shape.Fill = Brushes.Red;
                shape.MouseLeftButtonDown += Graphical_MouseDown;
                PointShapes.Add(point);
                canvas.Children.Add(shape);
            }
        }

        private void DrawXY()
        {
            YAxis = new Line
            {
                X1 = paddingWidth,
                Y1 = paddingWidth,
                X2 = paddingWidth,
                Y2 = canvasHeight - paddingWidth,
                Stroke = Brushes.LightGray,
                StrokeThickness = 1
            };

            canvas.Children.Add(YAxis);

            XAxis = new Line
            {
                X1 = paddingWidth,
                Y1 = canvasHeight - paddingWidth,
                X2 = canvasWidth - paddingWidth,
                Y2 = canvasHeight - paddingWidth,
                Stroke = Brushes.LightGray,
                StrokeThickness = 1
            };

            canvas.Children.Add(XAxis);
        }

        private void DrawArrow()
        {
            Polygon xArrow = new Polygon();
            xArrow.Points.Add(new Point(canvasWidth - paddingWidth, canvasHeight - paddingWidth));
            xArrow.Points.Add(new Point(canvasWidth - paddingWidth - arrowWidth, canvasHeight - paddingWidth + 2));
            xArrow.Points.Add(new Point(canvasWidth - paddingWidth - arrowWidth, canvasHeight - paddingWidth - 2));
            xArrow.Stroke = Brushes.LightGray;
            xArrow.StrokeThickness = 1;
            canvas.Children.Add(xArrow);

            Polygon yArrow = new Polygon();
            yArrow.Points.Add(new Point(paddingWidth, paddingWidth));
            yArrow.Points.Add(new Point(paddingWidth - 2, paddingWidth + arrowWidth));
            yArrow.Points.Add(new Point(paddingWidth + 2,  paddingWidth + arrowWidth));
            yArrow.Stroke = Brushes.LightGray;
            yArrow.StrokeThickness = 1;
            canvas.Children.Add(yArrow);
        }

        private double sdScale =1;
        private void DrawXRule()
        {
            System.Windows.Shapes.Line _line;
            TextBlock _textBlock;

            const double _minPixel = 20;        //长黑标线最小像素间距
            string _unit = "mm";                //记录尺度单位
            double _interval;                   //长黑标线实际距离
            double _intervalPixel;              //长黑标线实际像素距离

            double _scientificF;                //用来判断实际有效数字及尺度
            int _scientificE;
            string[] _strTemp = (_minPixel / sdScale).ToString("E").Split('E');
            double.TryParse(_strTemp[0], out _scientificF);
            int.TryParse(_strTemp[1], out _scientificE);
            if (_scientificE >= 2 || (_scientificE >= 1 && _scientificF >= 5))
            {
                _unit = "m";
                _scientificE -= 3;
            }

            //将间隔标准化
            if (_scientificF >= 5)
            {
                _interval = 10 * Math.Pow(10, _scientificE);
            }
            else if (_scientificF >= 2.5)
            {
                _interval = 5 * Math.Pow(10, _scientificE);
            }
            else
            {
                _interval = 2.5 * Math.Pow(10, _scientificE);
            }

            if (_unit == "mm")
            {
                _intervalPixel = _interval * sdScale;
            }
            else
            {
                _intervalPixel = _interval * 1000 * sdScale;
            }

            int _lineIndex = 0;
            double _width = XAxis.X2 - XAxis.X1 + paddingWidth - 5;
            double _pixelDistence = _intervalPixel / 5;     //单个小间隔像素距离
            for (double i = paddingWidth; i < _width; i += _pixelDistence)
            {
                _line = new System.Windows.Shapes.Line();
                if (_lineIndex % 5 == 0)
                {
                    _line.Stroke = Brushes.Black;
                    _line.StrokeThickness = 1;
                    _line.X1 = i;
                    _line.Y1 = canvasHeight - paddingWidth;
                    _line.X2 = i;
                    _line.Y2 = canvasHeight - paddingWidth + 8;

                    _textBlock = new TextBlock();
                    _textBlock.Text = (_interval * (_lineIndex / 5)).ToString();
                    _textBlock.FontSize = 8;
                    _textBlock.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
                    _textBlock.VerticalAlignment = System.Windows.VerticalAlignment.Top;
                    _textBlock.Margin = new Thickness(i - 5, canvasHeight - paddingWidth + 10, 0, 0);
                    canvas.Children.Add(_textBlock);
                }
                else
                {
                    _line.Stroke = Brushes.DimGray;
                    _line.StrokeThickness = 1;
                    _line.X1 = i;
                    _line.Y1 = canvasHeight - paddingWidth; ;
                    _line.X2 = i;
                    _line.Y2 = canvasHeight - paddingWidth + 4;
                }

                canvas.Children.Add(_line);

                _lineIndex++;
            }
        }

        private void DrawYRule()
        {
            System.Windows.Shapes.Line _line;
            TextBlock _textBlock;

            const double _minPixel = 20;        //长黑标线最小像素间距
            string _unit = "mm";                //记录尺度单位
            double _interval;                   //长黑标线实际距离
            double _intervalPixel;              //长黑标线实际像素距离

            double _scientificF;                //用来判断实际有效数字及尺度
            int _scientificE;
            string[] _strTemp = (_minPixel / sdScale).ToString("E").Split('E');
            double.TryParse(_strTemp[0], out _scientificF);
            int.TryParse(_strTemp[1], out _scientificE);
            if (_scientificE >= 2 || (_scientificE >= 1 && _scientificF >= 5))
            {
                _unit = "m";
                _scientificE -= 3;
            }

            //将间隔标准化
            if (_scientificF >= 5)
            {
                _interval = 10 * Math.Pow(10, _scientificE);
            }
            else if (_scientificF >= 2.5)
            {
                _interval = 5 * Math.Pow(10, _scientificE);
            }
            else
            {
                _interval = 2.5 * Math.Pow(10, _scientificE);
            }

            if (_unit == "mm")
            {
                _intervalPixel = _interval * sdScale;
            }
            else
            {
                _intervalPixel = _interval * 1000 * sdScale;
            }

            int _lineIndex = 0;
            double _width = YAxis.Y2;
            double _pixelDistence = _intervalPixel / 5;     //单个小间隔像素距离
            for (double i = _width; i > (paddingWidth+5); i -= _pixelDistence)
            {
                _line = new System.Windows.Shapes.Line();
                if (_lineIndex % 5 == 0)
                {
                    _line.Stroke = Brushes.Black;
                    _line.StrokeThickness = 1;
                    _line.X1 = paddingWidth;
                    _line.Y1 = i;
                    _line.X2 = paddingWidth - 8;
                    _line.Y2 = i;

                    _textBlock = new TextBlock();
                    _textBlock.Text = (_interval * (_lineIndex / 5)).ToString();
                    _textBlock.FontSize = 8;
                    _textBlock.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
                    _textBlock.VerticalAlignment = System.Windows.VerticalAlignment.Top;
                    _textBlock.Margin = new Thickness(22, i-5 , 0, 0);
                    _textBlock.LayoutTransform = new RotateTransform(90);
                    canvas.Children.Add(_textBlock);
                }
                else
                {
                    _line.Stroke = Brushes.DimGray;
                    _line.StrokeThickness = 1;
                    _line.X1 = paddingWidth;
                    _line.Y1 = i;
                    _line.X2 = paddingWidth - 4;
                    _line.Y2 = i;
                }

                canvas.Children.Add(_line);

                _lineIndex++;
            }
        }

        private PointCollection points;
        /// <summary>
        /// 多边形的点位置--真实数值数据，需要通过轴的GetLocation获取真实的位置
        /// </summary>
        public PointCollection Points
        {
            get { return points; }
            set { points = value; OnPropertyChanged("Points"); }
        }

        /// <summary>
        /// 控制图形的点位图形
        /// </summary>
        protected List<Point> PointShapes = new List<Point>();

        public event PropertyChangedEventHandler PropertyChanged;
        public virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
